﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Brain.Photon
{
    /// <summary>
    /// Manages Particle Emmiters
    /// </summary>
    public class ParticleSystem : IUpdateable, IDrawable
    {
        /// <summary>
        /// All the Emmiters this Particle System can have.
        /// YOU SHOULD'NT set any ParticleEmmiter here, or you will
        /// mess with all the System. Use AddEmmiter instead
        /// </summary>
        public ParticleEmitter[] Emitters { get; protected set; }

        public bool ShouldUpdate { get; set; }
        public bool ShouldDraw { get; set; }

        /// <summary>
        /// How much particles you want to spawn in 1 second. They will be spawned
        /// on the Position property
        /// </summary>
        public float ParticlesPerSecond
        {
            get { return particlesPerSecond; }
            set
            {
                particlesPerSecond = value;
                timeBetweenParticles = 1 / value;
            }
        }
        private float particlesPerSecond;
        private float timeBetweenParticles;
        
        /// <summary>
        /// World Object used for animating Particles the Particles source
        /// and many other stuff
        /// </summary>
        public WorldObject WorldObject;

        /// <summary>
        /// Intantiates a new ParticleSystem
        /// </summary>
        /// <param name="startMaxEmitters">The Maximum amount of Emmiters this ParticleSystem can handle</param>
        public ParticleSystem(ushort startMaxEmitters)
        {
            Emitters = new ParticleEmitter[startMaxEmitters];

            ShouldUpdate = true;
            ShouldDraw = true;
        }

        public int ActivePartices
        {
            get
            {
                int active = 0;
                for (int i = 0; i < Emitters.Length; i++)
                {
                    ParticleEmitter emitter = Emitters[i];
                    if (emitter != null)
                    {
                        active += emitter.ActiveParticles;
                    }
                }
                return active;
            }
        }

        /// <summary>
        /// How much Emmiters this Particle System currently have
        /// </summary>
        public int Count { get { return count; } }

        private int count = 0;
        /// <summary>
        /// Adds an Emmiter to this Particle System. Automatically
        /// resizes if the Particle System isn't great enough
        /// </summary>
        public virtual void AddEmitter(ParticleEmitter emitter)
        {
            if (count == Emitters.Length)
            {
                Resize(this.Emitters.Length * 2);
            }
            emitter.Parent = this;
            Emitters[count] = emitter;
            count++;
        }

        /// <summary>
        /// Resizes this ParticleSystem, so it can handle more Emmiters
        /// </summary>
        /// <param name="maxEmmiters"></param>
        public virtual void Resize(int maxEmmiters)
        {
            ParticleEmitter[] arrey = new ParticleEmitter[maxEmmiters];
            Emitters.CopyTo(arrey, 0);
            this.Emitters = arrey;
        }

        /// <summary>
        /// Spawns a Particle in all the Emmiters on the desired center Position
        /// </summary>
        /// <param name="centerPosition">The position to spawn the particle</param>
        public virtual void SpawnParticle(Vector3 centerPosition)
        {
            for (ushort i = 0; i < count; i++)
            {
                ParticleEmitter e = Emitters[i];
                e.SpawnParticle(centerPosition);
            }
        }
        /// <summary>
        /// Spawns a Particle in all the Emmiters on the desired center Position
        /// </summary>
        /// <param name="centerPosition">The position to spawn the particle</param>
        public virtual void SpawnParticle(Vector3 centerPosition, Vector3 linearVelocity, Vector3 angularVelocity)
        {
            for (ushort i = 0; i < count; i++)
            {
                ParticleEmitter e = Emitters[i];
                e.SpawnParticle(centerPosition, linearVelocity, angularVelocity);
            }
        }

        private float timeLeft;
        /// <summary>
        /// Updates the Particle System
        /// </summary>
        public virtual void Update()
        {
            if (ParticlesPerSecond != 0)
            {
                float time = (float)Engine.Instance.GameTime.ElapsedGameTime.TotalSeconds;

                Vector3 velocity = (WorldObject.Position - WorldObject.LastPosition) / time;
                float timeToSpend = timeLeft + time;

                float currentTime = -timeLeft;

                while (timeToSpend > timeBetweenParticles)
                {
                    currentTime += timeBetweenParticles;
                    timeToSpend -= timeBetweenParticles;

                    // Work out the optimal position for this particle. This will produce
                    // evenly spaced particles regardless of the object speed, particle
                    // creation frequency, or game update rate.
                    float mu = currentTime / time;

                    Vector3 position = Vector3.Lerp(WorldObject.LastPosition, WorldObject.Position, mu);

                    // Create the particle.
                    SpawnParticle(position, velocity, Vector3.Zero);
                }
                WorldObject.Position = WorldObject.Position;
                timeLeft = timeToSpend;
            }
            for (ushort i = 0; i < count; i++)
            {
                ParticleEmitter e = Emitters[i];
                e.Update();
            }
        }

        /// <summary>
        /// Draws the Particle System
        /// </summary>
        public virtual void Draw()
        {
            for (ushort i = 0; i < count; i++)
            {
                ParticleEmitter e = Emitters[i];
                e.Draw();
            }
        }
    }
}
